package com.business.action.wechat;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.business.bean.system.UserBean;
import com.business.wechat.bean.WxUserBean;
import com.business.wechat.service.WeixinService;
import com.business.wechat.service.WeixinUtils;
import com.business.wechat.util.ReturnModel;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import net.sf.rose.file.util.FileUtils;
import net.sf.rose.jdbc.KeyGenerator;
import net.sf.rose.jdbc.PageBean;
import net.sf.rose.jdbc.dao.BeanDAO;
import net.sf.rose.jdbc.query.BeanSQL;
import net.sf.rose.jdbc.service.Service;
import net.sf.rose.web.util.WebUtils;

/**
 * @author: fengjian
 * @date: 2018/08/20
 * @description:对接微信公众号的API
 *
 */
@Controller
@RequestMapping("/any/wechat")
public class WechatAction extends WechatGenericController {

	/**
	 * 微信公众号webservice主服务接口，提供与微信服务器的信息交互
	 */
	@RequestMapping(value = "/{weixinName}/core.do")
	public void wechatCore(@PathVariable("weixinName") String weixinName, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=utf-8");
		response.setStatus(HttpServletResponse.SC_OK);

		String signature = request.getParameter("signature");
		String nonce = request.getParameter("nonce");
		String timestamp = request.getParameter("timestamp");

		WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
		if (!wc.getMpService().checkSignature(timestamp, nonce, signature)) {
			// 消息签名不正确，说明不是公众平台发过来的消息
			response.getWriter().println("非法请求");
			return;
		}

		String echoStr = request.getParameter("echostr");
		if (StringUtils.isNotBlank(echoStr)) {
			// 说明是一个仅仅用来验证的请求，回显echostr
			String echoStrOut = String.copyValueOf(echoStr.toCharArray());
			response.getWriter().println(echoStrOut);
			return;
		}

		String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type")) ? "raw"
				: request.getParameter("encrypt_type");

		if ("raw".equals(encryptType)) {
			// 明文传输的消息
			WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream());
			// 特殊处理，如果是关注公众号，就把微信名称加入请求参数中
			if (inMessage.getMsgType().equals("subscribe")) {
				inMessage.setCardId(weixinName);
			}
			this.logger.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
			WxMpXmlOutMessage outMessage = wc.getRouter().route(inMessage);
			if (outMessage == null) {
				response.getWriter().write("");
			} else {
				response.getWriter().write(outMessage.toXml());
			}
			return;
		}

		if ("aes".equals(encryptType)) {
			// 是aes加密的消息
			String msgSignature = request.getParameter("msg_signature");
			WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), wc.getConfigStorage(),
					timestamp, nonce, msgSignature);
			// 特殊处理，如果是关注公众号，就把微信名称加入请求参数中
			if (inMessage.getMsgType().equals("subscribe")) {
				inMessage.setCardId(weixinName);
			}
			this.logger.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
			WxMpXmlOutMessage outMessage = wc.getRouter().route(inMessage);
			if (outMessage == null) {
				response.getWriter().write("");
			} else {
				response.getWriter().write(outMessage.toEncryptedXml(wc.getConfigStorage()));
			}
			return;
		}
		response.getWriter().println("不可识别的加密类型");
	}

	/**
	 * 通过openid获得基本用户信息 详情请见:
	 * http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
	 * 
	 * @param openid openid
	 * @param lang   zh_CN, zh_TW, en
	 */
	@ResponseBody
	@RequestMapping(value = "/{weixinName}/getUserInfo.do")
	public PageBean getUserInfo(@PathVariable("weixinName") String weixinName, HttpServletResponse response,
			@RequestParam(value = "openid") String openid,
			@RequestParam(value = "lang", defaultValue = "zh_CN") String lang) {
		PageBean page = new PageBean();
		WxMpUser wxMpUser = null;
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			wxMpUser = wc.getMpService().getUserService().userInfo(openid, lang);
			page.setData(wxMpUser);
		} catch (WxErrorException e) {
			page.setSuccess(false);
			page.setMessage(e.getError().toString());
			this.logger.error(e.getError().toString());
		}
		return page;
	}

	/**
	 * 通过code获得基本用户信息 详情请见:
	 * http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
	 * 
	 * @param code code
	 * @param lang zh_CN, zh_TW, en
	 */
	@RequestMapping(value = "/{weixinName}/getOAuth2UserInfo.do")
	public void getOAuth2UserInfo(@PathVariable("weixinName") String weixinName, Service service,
			HttpServletResponse response, @RequestParam(value = "code") String code,
			@RequestParam(value = "lang", defaultValue = "zh_CN") String lang) {
		ReturnModel returnModel = new ReturnModel();
		WxMpOAuth2AccessToken accessToken;
		WxMpUser wxMpUser;
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			accessToken = wc.getMpService().oauth2getAccessToken(code);
			wxMpUser = wc.getMpService().getUserService().userInfo(accessToken.getOpenId(), lang);
			returnModel.setResult(true);
			if (wxMpUser != null) {
				BeanDAO dao = new BeanDAO(service);
				BeanSQL query = dao.getQuerySQL();
				query.setEntityClass(WxUserBean.class);
				query.createSql("openId", wxMpUser.getOpenId());
				WxUserBean user = dao.load();
				returnModel.setDatum(user);
			}
			renderString(response, returnModel);
		} catch (WxErrorException e) {
			returnModel.setResult(false);
			returnModel.setReason(e.getError().toString());
			renderString(response, returnModel);
			this.logger.error(e.getError().toString());
		}
	}

	/**
	 * 用code换取oauth2的openid 详情请见:
	 * http://mp.weixin.qq.com/wiki/1/8a5ce6257f1d3b2afb20f83e72b72ce9.html
	 * 
	 * @param code code
	 */
	@RequestMapping(value = "/{weixinName}/getOpenid.do")
	public void getOpenid(@PathVariable("weixinName") String weixinName, HttpServletResponse response,
			@RequestParam(value = "code") String code) {
		ReturnModel returnModel = new ReturnModel();
		WxMpOAuth2AccessToken accessToken;
		this.logger.info("code:" + code);
		System.out.println("-----------getOpenid-----------");
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			accessToken = wc.getMpService().oauth2getAccessToken(code);
			returnModel.setResult(true);
			returnModel.setDatum(accessToken.getOpenId());
			renderString(response, returnModel);
		} catch (WxErrorException e) {
			returnModel.setResult(false);
			returnModel.setReason(e.getError().toString());
			renderString(response, returnModel);
			this.logger.error(e.getError().toString());
		}
	}

	@RequestMapping(value = "/{weixinName}/getAccessToken.do")
	public String getAccessToken(@PathVariable("weixinName") String weixinName) {
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			String accessToken = wc.getMpService().getAccessToken();
			return accessToken;
		} catch (WxErrorException e) {
			e.printStackTrace();
		}
		return null;
	}

	@ResponseBody
	@RequestMapping(value = "/{weixinName}/getJsapiTicket.do")
	public String getJsapiTicket(@PathVariable("weixinName") String weixinName) {
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			String jsapiTicket = wc.getMpService().getJsapiTicket();
			return jsapiTicket;
		} catch (WxErrorException e) {
			e.printStackTrace();
		}
		return null;
	}

	@ResponseBody
	@RequestMapping(value = "/{weixinName}/createJsapiSignature.do")
	public WxJsapiSignature createJsapiSignature(@PathVariable("weixinName") String weixinName, String url) {
		try {
			WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
			WxJsapiSignature signature = wc.getMpService().createJsapiSignature(url);
			return signature;
		} catch (WxErrorException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 用户请求地址重定向获取用户openId
	 * 
	 * @throws IOException
	 */
	@RequestMapping(value = "/{weixinName}/getOpenidRedirect.do")
	public void getOpenidRedirect(@PathVariable("weixinName") String weixinName, HttpServletResponse response)
			throws IOException {
		WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
		String root = wc.getWxConfigBean().getServerUrl();
		String url = root + "/any/wechat/" + weixinName + "/redirectWxUrl.do";
		url = wc.getMpService().oauth2buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_BASE, null);
		System.out.println(url);
		response.sendRedirect(url);
	}

	/**
	 * 用户请求地址重定向获取用户openId
	 * 
	 * @throws IOException
	 */
	@RequestMapping(value = "/{weixinName}/redirectWxUrl.do")
	public void redirectWxUrl(@PathVariable("weixinName") String weixinName, String to_page,
			@RequestParam(value = "code") String code, HttpServletResponse response, HttpServletRequest request)
			throws IOException {
		WeixinService wc = WeixinUtils.getWeixinBean(weixinName);
		String root = wc.getWxConfigBean().getServerUrl();
		String url = root + '/' + to_page;
		WxMpOAuth2AccessToken accessToken = null;
		try {
			System.out.println("-----------getOpenid-----------");
			System.out.println("code:" + code);
			accessToken = wc.getMpService().oauth2getAccessToken(code);
		} catch (WxErrorException e) {
			this.logger.error(e.getError().toString());
		}
		String openId = accessToken.getOpenId();
		url = url + "?openId=" + openId;
		Map<String, Object> map = WebUtils.getRequestData(request);
		// 去掉系统传过来的参数
		map.remove("to_page");
		map.remove("code");
		map.remove("state");
		// 加上系统必须的TOKEN参数
		UserBean user = new UserBean();
		String token = WebUtils.setUserBeanCache(request, user);
		map.put("_token", token);
		for (String name : map.keySet()) {
			Object obj = map.get(name);
			if (obj != null && !obj.equals("")) {
				url = url + '&' + name + '=' + obj.toString();
			}
		}
		System.out.println(url);
		response.sendRedirect(url);
	}

	/**
	 * 微信端用户上传图片
	 * 
	 * @param weixinName
	 * @param request
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/{weixinName}/uploadImage.do")
	public PageBean uploadImage(@PathVariable("weixinName") String weixinName, HttpServletRequest request) {
		PageBean res = new PageBean();
		Map<String, Object> map = WebUtils.getRequestData(request);
		String server = map.get("media_id").toString();
		// System.out.println(server);
		WxMpService service = WeixinUtils.getWeixinBean(weixinName).getMpService();
		try {
			File uploadFile = service.getMaterialService().mediaDownload(server);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
			String ymd = sdf.format(new Date());
			File path = new File(FileUtils.IMAGE_PATH, ymd);
			// 创建文件夹
			if (!path.exists()) {
				path.mkdirs();
			}
			String origName = uploadFile.getAbsolutePath();
			String subfix = origName.substring(origName.lastIndexOf("."));
			subfix = KeyGenerator.getSystemUUID() + subfix;
			File target = new File(path, subfix);
			FileUtils.copy(uploadFile, target);
			res.setData('/' + target.getParentFile().getName() + '/' + subfix);
		} catch (Exception e1) {
			e1.printStackTrace();
			res.setSuccess(false);
			res.setMessage("微信上传图片失败...");
		}
		return res;
	}
}